from datetime import datetime
import json
import os
from openai import OpenAI
from tqsdk.ta import *
import logging

class BybridData:
    dk:pd.DataFrame
    hk:pd.DataFrame
    mk:pd.DataFrame
    m30k:pd.DataFrame
    m15k:pd.DataFrame
    m5k:pd.DataFrame
    
class BybridSignal:
    def __init__(self, ds:OpenAI,model:str,symbol:str,remind:int):
        self.ds = ds
        self.env_msg=[
            {"role": "system", "content": "你是一个期货行情分析员，我为您提供行情数据你需要根据数据给出买卖信号，注意您只输出-1(卖出)0(观望)+1(买入)，不要输出其他描述信息"},
            {"role": "system", "content": "最近20日的K线数据DK；1小时周期：DMA，ATR，BOLL,RSI，KDJ，MACD；30分钟周期：DMA，ATR，BOLL,RSI，KDJ，MACD；15分钟周期：DMA，ATR，BOLL,RSI，KDJ，MACD；5分钟周期：ASI，MFI，DFMA，BBI，ATR，CCI，PSY，BOLL，BIAS，RSI，KDJ，MACD；1分钟周期：ASI，MFI，DFMA，BBI，ATR，CCI，PSY，BOLL，BIAS，RSI，KDJ，MACD"},
            {"role": "system", "content": "注意你只能通过上面提供的数据不能基于假设做出判断，控制每日交易次数避免频繁交易，控制日内回撤，过滤掉震荡周期"}
        ]
        self.model = model
        self.remind = remind
        self.history_file = f"persist/hybrid_signal_{symbol}.json"
        self.history : list = self.load_history_data()
        

    def load_history_data(self):
        #加载运行时数据
        if os.path.exists(self.history_file):
            with open(self.history_file, 'r') as file:
                return json.load(file)
        return []

    def save_history_json(self,msg,res):
        if len(self.history) > self.remind: 
            self.history.pop(0)
        self.history.append({"message":msg,"result":res})
        #保存运行时数据
        with open(self.history_file, 'w') as file:
            json.dump(self.history, file)

    
    def reasoning_signal(self,data:BybridData,target_time:datetime):
        
        #使用ds推理，并根据结果同步持仓
        dks = data.dk[["datetime","open", "high", "low", "close","volume"]]
        last_reasoning_time = 0
        if target_time is not None :
            last_reasoning_time = target_time.timestamp()    
        dma1h = DMA(data.hk,5,10,20)
        atr1h = ATR(data.hk,14)
        boll1h = BOLL(data.hk,26,2)
        rsi1h = RSI(data.hk,7)
        kdj1h = KDJ(data.hk,9,3,3)
        macd1h = MACD(data.hk,12,26,9)
        data1h = pd.concat([data.hk[["datetime","open", "high", "low", "close","volume"]],dma1h, atr1h, boll1h, rsi1h,kdj1h,macd1h], axis=1)
        dma30m = DMA(data.m30k,5,10,20)
        atr30m = ATR(data.m30k,14)
        boll30m = BOLL(data.m30k,26,2)
        rsi30m = RSI(data.m30k,7)
        kdj30m = KDJ(data.m30k,9,3,3)
        macd30m = MACD(data.m30k,12,26,9)

        data30m = pd.concat([data.m30k[["datetime","open", "high", "low", "close","volume"]],dma30m, atr30m, boll30m, rsi30m,kdj30m,macd30m], axis=1)

        dma15m = DMA(data.m15k,5,10,20)
        atr15m = ATR(data.m15k,14)
        boll15m = BOLL(data.m15k,26,2)
        rsi15m = RSI(data.m15k,7)
        kdj15m = KDJ(data.m15k,9,3,3)
        macd15m = MACD(data.m15k,12,26,9)
        data15m = pd.concat([data.m15k[["datetime","open", "high", "low", "close","volume"]],dma15m, atr15m, boll15m, rsi15m,kdj15m,macd15m], axis=1)

        asi5m = ASI(data.m5k)
        mfi5m = MFI(data.m5k,14)
        #BOLL，
        bbi5m = BBI(data.m5k,3,6,12,24)
        atr5m = ATR(data.m5k,14)
        cci5m = CCI(data.m5k,14)
        psy5m = PSY(data.m5k,12,6)
        boll5m = BOLL(data.m5k,26,2)
        #BIAS，WR，RSI，KDJ，MACD
        bias5m = BIAS(data.m5k,6)
        #wr = WR(mk.close,mk.high,mk.low)[-60:]
        rsi5m = RSI(data.m5k,7)
        kdj5m = KDJ(data.m5k,9,3,3)
        macd5m = MACD(data.m5k,12,26,9)

        data5m = pd.concat([data.m5k[["datetime","open", "high", "low", "close","volume"]],asi5m, mfi5m, bbi5m, atr5m,cci5m,psy5m,boll5m,bias5m,rsi5m,kdj5m,macd5m], axis=1)

        asi1m = ASI(data.mk)
        mfi1m = MFI(data.mk,14)
        #BOLL，
        bbi1m = BBI(data.mk,3,6,12,24)
        atr1m = ATR(data.mk,14)
        cci1m = CCI(data.mk,14)
        psy1m = PSY(data.mk,12,6)
        boll1m = BOLL(data.mk,26,2)
        #BIAS，WR，RSI，KDJ，MACD
        bias1m = BIAS(data.mk,6)
        #wr = WR(mk.close,mk.high,mk.low)[-60:]
        rsi1m = RSI(data.mk,7)
        kdj1m = KDJ(data.mk,9,3,3)
        macd1m = MACD(data.mk,12,26,9)

        data1m = pd.concat([data.mk[["datetime","open", "high", "low", "close","volume"]],asi1m, mfi1m, bbi1m, atr1m,cci1m,psy1m,boll1m,bias1m,rsi1m,kdj1m,macd1m], axis=1)

        req_msg = self.env_msg.copy()
        req_msg.append({'role': 'system', 'content': f"DK (last 20 days)：\n{dks.round(0).astype(int).to_string(index=False)}\n\n"})
        for item in self.history: 
            req_msg.append({'role': 'user', 'content': item["message"]})
            req_msg.append({'role': 'assistant', 'content': item["result"]})
        
        last_msg:str = self.data_format_string(data1h,last_reasoning_time,"1小时周期数据")
        last_msg += self.data_format_string(data30m,last_reasoning_time,"30分钟周期数据")
        last_msg += self.data_format_string(data15m,last_reasoning_time,"15分钟周期数据")
        last_msg += self.data_format_string(data5m,last_reasoning_time,"5分钟周期数据")
        last_msg += self.data_format_string(data1m,last_reasoning_time,"1分钟周期数据")
        #print(self.last_msg)
        last_result = 0
        if(len(last_msg)>0):
            req_msg.append({'role': 'user', 'content': last_msg})
        
            response = self.ds.chat.completions.create(
                model=self.model,
                #model="deepseek-r1:32b",
                messages=req_msg,
                stream=False
            )
            print(response.choices[0].message.content)
            last_result = int(response.choices[0].message.content.strip())
            logging.info(f"{datetime.now()}:position-> {last_result} reasoning_content:{response.choices[0].message.reasoning_content}")
            
            self.save_history_json(last_msg,last_result)
        return last_result
    
    def data_format_string(self,data:pd.DataFrame,last_time,msg:str):
        data["datetime"] = (data["datetime"]/1000000000.0).astype(float)
        data = data[data["datetime"]>=last_time]
        result = ""
        if len(data) > 0:
            result = f"{msg}：\n{data.round(0).to_string(index=False)}\n\n"
        return result
    
    
        